package org.setec.utils.xml;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class XMLLoader {

    protected static List<String> getStringAttributes(Document document, String path, String attributeName){
        List<String> result = new ArrayList();
        String[] pathElements = path.split("\\|");
        List<Node> nodes = new ArrayList();
        lookup(nodes, document.getFirstChild(), pathElements, 0);
        for( Node node : nodes ){
            Node attribute = node.getAttributes().getNamedItem(attributeName);
            if( attribute!=null ){
                String attributeValue = attribute.getNodeValue();
                result.add(attributeValue);
            } else {
                System.out.println("Warning: XMLLoader - can't find attribute " + attributeName + " at path " + path);
            }
        }
        return result;
    }

    protected static String getStringAttribute(Document document, String path, String attributeName){
        List<String> attributes = getStringAttributes(document, path, attributeName);
        if( attributes.size()==1 ){
            return attributes.get(0);
        } else {
            throw new IllegalStateException("Invalid number of attributes at:" + path + "@" + attributeName);
        }
    }

    protected static List<String> getStringAttributes(Document document, String path, String attributeName, String filter){
        List<String> filterEntries = Arrays.asList(filter.split(";"));
        List<String[]> filterList = new ArrayList();
        for( String filterEntry : filterEntries ){
            String filterPath = filterEntry.split("@")[0];
            String filterAttribute = filterEntry.split("@")[1].split("=")[0];
            String filterAttributeValue = filterEntry.split("@")[1].split("=")[1];
            filterList.add(new String[] { filterPath, filterAttribute, filterAttributeValue });
        }

        List<String> result = new ArrayList();
        String[] pathElements = path.split("\\|");
        List<Node> nodes = new ArrayList();
        lookup(nodes, document.getFirstChild(), pathElements, 0, filterList);
        for( Node node : nodes ){
            Node attribute = node.getAttributes().getNamedItem(attributeName);
            if( attribute!=null ){
                String attributeValue = attribute.getNodeValue();
                result.add(attributeValue);
            } else {
                System.out.println("Warning: XMLLoader - can't find attribute " + attributeName + " at path " + path);
            }
        }
        return result;

    }

    protected static void lookup(List nodes, Node node, String[] pathElements, int pathCursor, List<String[]> filterList){

        if( pathCursor>=pathElements.length ){
            return;
        }
        if( node.getNodeName().equals(pathElements[pathCursor]) ){

            boolean filterPass = false;

            for( String[] filterDetails : filterList ){
                String[] filterPathElements = filterDetails[0].split("\\|");

                boolean filterIsForThisNode = true;
                for( int i = 0; i <= pathCursor; i ++ ){
                    if( !pathElements[i].equals(filterPathElements[i]) ){
                        filterIsForThisNode = false;
                    }
                }
                if( !filterIsForThisNode ){
                    continue;//this filter is not for current node path
                }

                if( filterPathElements.length == pathCursor+1 ){
                    Node attribute = node.getAttributes().getNamedItem(filterDetails[1]);
                    if( filterDetails[2].equals(attribute.getNodeValue() ) ){
                        filterPass = true;
                    }
                } else {
                    filterPass = true;
                }

            }

            if( !filterPass ){
                return;
            }

            if( pathElements.length == pathCursor+1 ){
                nodes.add(node);
            } else {
                NodeList childNodes = node.getChildNodes();
                for( int nodeIndex = 0; nodeIndex < childNodes.getLength(); nodeIndex++ ){
                    lookup(nodes, childNodes.item(nodeIndex), pathElements, pathCursor + 1 );
                }
            }
        }
    }


    protected static void lookup(List nodes, Node node, String[] pathElements, int pathCursor){
        if( pathCursor>=pathElements.length ){
            return;
        }
        if( node.getNodeName().equals(pathElements[pathCursor]) ){
            if( pathElements.length == pathCursor+1 ){
                nodes.add(node);
            } else {
                NodeList childNodes = node.getChildNodes();
                for( int nodeIndex = 0; nodeIndex < childNodes.getLength(); nodeIndex++ ){
                    lookup(nodes, childNodes.item(nodeIndex), pathElements, pathCursor + 1 );
                }
            }
        }
    }

}
